package cn.faifai.framework.exception;

import cn.hutool.core.util.ObjectUtil;
import cn.faifai.common.component.R;
import cn.faifai.common.exception.ServiceException;
import cn.faifai.common.exception.file.FileHashConflictException;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;

@Slf4j
@RestControllerAdvice
/**
 * @RestControllerAdvice 是 Spring Framework 中的一个注解，它结合了 @ControllerAdvice 和 @ResponseBody 的功能。
 * 这个注解主要用于定义全局的控制器增强，比如全局异常处理、全局数据绑定、全局数据预处理等。使用 @RestControllerAdvice，
 * 你可以创建一个类来集中处理跨多个 @RestController 的横切关注点（cross-cutting concerns），比如异常处理和响应体构建。
 *
 * 全局异常处理：通过定义 @ExceptionHandler 方法，你可以捕获并处理来自多个控制器的异常，而无需在每个控制器中重复相同的异常处理代码。
 * 全局数据预处理：使用 @InitBinder 或 @ModelAttribute 方法，你可以对请求数据进行预处理，比如格式化日期、设置默认值等。
 * 全局响应体构建：由于 @RestControllerAdvice 隐含了 @ResponseBody，因此你可以直接返回对象或集合，Spring 会自动将其转换为 JSON 或 XML 等格式。
 */
public class GlobalExceptionHandler {

    /**
     * 业务异常
     */
    @ExceptionHandler(ServiceException.class)
    public R<Void> handleServiceException(ServiceException e, HttpServletRequest request) {
        log.error(e.getMessage());
        Integer code = e.getCode();
        return ObjectUtil.isNotNull(code) ? R.fail(code, e.getMessage()) : R.fail(e.getMessage());
    }

    /**
     * 系统异常
     */
    @ExceptionHandler(Exception.class)
    public R<Void> handleException(Exception e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生系统异常.", requestURI, e);
        return R.fail(e.getMessage());
    }

    /**
     * 请求参数类型不匹配
     */
    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public R<Void> handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI);
        return R.fail(String.format("请求参数类型不匹配，参数[%s]要求类型为：'%s'，但输入值为：'%s'", e.getName(), e.getRequiredType().getName(), e.getValue()));
    }

    /**
     * 拦截未知的运行时异常
     */
    @ExceptionHandler(RuntimeException.class)
    public R<Void> handleRuntimeException(RuntimeException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生未知异常.", requestURI, e);
        return R.fail(e.getMessage());
    }

    /**
     * 输入参数非法异常
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public R<Void> handleIllegalArgumentException(IllegalArgumentException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生非法参数异常.", requestURI, e);
        return R.fail(e.getMessage());
    }

    /**
     * 文件哈希冲突异常
     */
    @ExceptionHandler(FileHashConflictException.class)
    public R<Object> handleFileHashConflictException(FileHashConflictException e, HttpServletRequest request) {
        String requestURI = request.getRequestURI();
        log.error("请求地址'{}',发生文件哈希冲突异常.", requestURI, e);
        return R.fail(e.getMessage(), e.getData());
    }
}
